package com.inspur.dgov.bsp.system.controller;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.inspur.dgov.bsp.system.entity.PubConfig;
import com.inspur.dgov.bsp.system.entity.PubDict;
import com.inspur.dgov.bsp.system.service.PubConfigService;
import com.inspur.dgov.bsp.system.service.PubDictService;
import com.inspur.dgov.bsp.system.service.TreeService;
import com.inspur.dgov.bsp.system.vo.DictVO;
import com.inspur.dgov.bsp.system.wrapper.PubDictWrapper;
import com.inspur.dgov.common.boot.operation.RedissonCollection;
import com.inspur.dgov.common.secure.dto.SecureUser;
import com.inspur.dgov.common.secure.utils.SecureUtil;
import com.inspur.dgov.common.tool.api.R;
import com.inspur.dgov.common.tool.constant.AppConstant;
import com.inspur.dgov.common.tool.node.TreeNode;
import com.inspur.dgov.common.tool.node.TreeNodeUtil;
import com.inspur.dgov.common.tool.utils.UniqueIdGenerator;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 字典项信息 前端控制器
 * </p>
 *
 * @author chiyupei
 * @since 2020-04-17
 */
@RestController
@RequestMapping("/dict")
@Api(value = "字典项管理", tags = "字典项接口")
public class PubDictController {

    @Value("${tenant.default.id}")
    private String defaultTenantId;

    @Autowired
    private PubDictService pubDictService;

    @Autowired
    private PubConfigService pubConfigService;

    @Autowired
    private TreeService treeService;

    @Autowired
    private RedissonCollection redissonCollection;

    /**
     * 字典项分页列表
     *
     * @param configId
     * @param query
     * @param page
     * @return
     */
    @PostMapping("/page")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "configId", value = "字典类别ID", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "query", value = "查询条件", paramType = "query", dataType = "String")
    })
    @ApiOperation(value = "字典项分页列表", notes = "传入字典类别ID或查询条件", position = 1)
    public R<IPage<DictVO>> page(@RequestParam(value="configId", required = false) String configId,
                                 @RequestParam(value="query", required = false) String query, Page page) {
        SecureUser curUser = SecureUtil.getUser();
        String tenantId = curUser.getTenantId();
        Map<String, Object> params = new HashMap<>();
        params.put("query", query);

        if (StrUtil.isNotBlank(configId)) {
            //判断是否是字典等级
            if (StrUtil.equalsAny(configId, new String[]{"0", "1", "2", "3"})) {
                params.put("type", configId);
            } else {
                params.put("configId", configId);
            }
        }
        if (!StrUtil.equals(this.defaultTenantId, tenantId)) {
            params.put("tenantId", tenantId);
        }
        IPage<PubDict> pages = this.pubDictService.selectDictPage(page, params);
        return R.data(PubDictWrapper.build().pageVO(pages));
    }

    /**
     * 唯一性校验
     *
     * @param value
     * @param id
     * @return
     */
    @PostMapping("/verifyUnique")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "value", value = "字典编码", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "id", value = "字典ID", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "configId", value = "字典类别ID", paramType = "query", dataType = "String")
    })
    @ApiOperation(value = "字典唯一性校验", notes = "传入字典编码、字典ID和字典类别ID", position = 2)
    public R verifyUnique(@RequestParam(value = "value", required = true) String value,
                          @RequestParam(value = "id", required = false) String id,
                          @RequestParam(value = "configId", required = true) String configId) {
        if (StrUtil.hasEmpty(value, configId)) {
            return R.fail("接口调用不合法");
        }

        QueryWrapper<PubDict> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PubDict::getCode, value)
                .eq(PubDict::getConfigId, configId);
        if (StrUtil.isNotEmpty(id)) {
            queryWrapper.lambda().ne(PubDict::getId, id);
        }

        //查出满足条件的所有记录
        List<PubDict> list = this.pubDictService.list(queryWrapper);
        if (ObjectUtil.isEmpty(list)) {
            return R.success("");
        }
        return R.fail("该字典编码已被使用");
    }

    /**
     * 新增字典项
     *
     * @param dict
     * @return
     */
    @PostMapping("/add")
    @ApiOperation(value = "新增字典项", notes = "传入字典项信息", position = 3)
    public R add(@RequestBody PubDict dict) {
        SecureUser curUser = SecureUtil.getUser();
        LocalDateTime now = LocalDateTime.now();
        Long id = UniqueIdGenerator.generateId();
        dict.setId(id);
        dict.setCreator(Long.valueOf(curUser.getUserId()));
        dict.setCreateTime(now);
        dict.setStatus(AppConstant.DB_STATUS_NORMAL);
        //获取设置字典类别相关字段
        PubConfig config = this.pubConfigService.getById(dict.getConfigId());
        dict.setConfigCode(config.getCode());
        dict.setType(config.getType());
        dict.setTenantId(Long.valueOf(curUser.getTenantId()));
        boolean ret = this.pubDictService.save(dict);
        //增加Redis中数据
        List<PubDict> dictList = this.redissonCollection.getList(dict.getConfigCode());
        if (null != dictList) {
            dictList.add(dict);
        } else {
            List<PubDict> newList = new ArrayList<>();
            newList.add(dict);
            this.redissonCollection.setListValues(dict.getConfigCode(), newList, Long.valueOf(60 * 60 * 12 * 1000));
        }
        return R.status(ret);
    }

    /**
     * 更新字典项
     *
     * @param dict
     * @return
     */
    @PostMapping("/update")
    @ApiOperation(value = "更新字典项", notes = "传入字典项信息", position = 4)
    public R update(@RequestBody PubDict dict) {
        boolean ret = this.pubDictService.updateById(dict);
        //更新Redis数据
        List<PubDict> dictList = this.redissonCollection.getList(dict.getConfigCode());
        if (null != dictList && dictList.size() > 0) {
            dictList.removeIf(item -> item.getId().equals(dict.getId()));
            dictList.add(dict);
        }
        return R.status(ret);
    }

    /**
     * 删除字典项
     */
    @PostMapping("/remove")
    @ApiOperation(value = "删除字典项", notes = "传入字典项ID", position = 5)
    public R remove(@RequestBody PubDict dict) {
        //检查是否有下级
        QueryWrapper<PubDict> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(PubDict::getParentId, dict.getId());
        int count = this.pubDictService.count(queryWrapper);
        if (count > 0) {
            return R.fail("存在下级字典项，不能删除");
        }
        boolean ret = this.pubDictService.removeById(dict);
        //删除Redis中数据
        List<PubDict> dictList = this.redissonCollection.getList(dict.getConfigCode());
        if (null != dictList && dictList.size() > 0) {
            dictList.removeIf(item -> item.getId().equals(dict.getId()));
        }
        return R.status(ret);
    }

    /**
     * 字典树
     */
    @GetMapping("/dictTree/{configId}")
    @ApiOperation(value = "通过字典类别ID查询字典树", notes = "传入字典类别ID", position = 6)
    public R<List<TreeNode>> dictTree(@PathVariable String configId) {
        List<TreeNode> tree = new ArrayList<>();
        Map<String, Object> param = new HashMap<>();
        param.put("configId", configId);
        tree.addAll(this.treeService.dictTree(param));
        return R.data(TreeNodeUtil.merge(tree));
    }

    /**
     * 通过字典类别编码获取字典树
     *
     * @param configCode
     */
    @GetMapping("/dictTreeByCode/{configCode}")
    @ApiOperation(value = "通过字典类别编码获取字典树", notes = "传入字典类别编码", position = 7)
    public R<List<TreeNode>> dictTreeByCode(@PathVariable String configCode) {
        List<TreeNode> tree = new ArrayList<>();
        //先从Redis中获取
        List<PubDict> dictList = this.redissonCollection.getList(configCode);
        if (null != dictList && dictList.size() > 0) {
            dictList.sort(Comparator.comparing(PubDict::getSortOrder));
            for (PubDict dict : dictList) {
                TreeNode node = new TreeNode();
                node.setId(dict.getId());
                node.setParentId(dict.getParentId());
                node.setTitle(dict.getName());
                tree.add(node);
            }
        } else {
            Map<String, Object> param = new HashMap<>();
            param.put("configCode", configCode);
            tree.addAll(this.treeService.dictTree(param));
        }
        return R.data(TreeNodeUtil.merge(tree));
    }
}
